import React from 'react';
import { ITableProps, RowDataType } from './Table.types';
import {
    StyledTBody,
    StyledTD,
    StyledTHead,
    StyledTable,
    StyledTH,
    StyledTR
} from './Table.styled';
import Checkbox from '../Checkbox/Checkbox';

/** 
 * @function Table - Компонент таблицы. 
 * 
 * @typedef { Object } ITableProps - Тип для пропсов компонента Table.
 * @property { string } className - Устанавливает пользовательские классы на элементе <table>
 * @property { HeaderColumnType[] } columnList - Массив заголовков таблицы.
 * @property { RowDataType[] } rowList -  Массив с данными.
 * @property { boolean } enableActions - Если true добавит в таблицу колонку с actions.
 * @property { boolean } enableCheckbox - Если true отобразит checkbox для выбора строк таблицы.
 * @property { function } onSelect - Колбек, который передает id одной текущей строки.
 * @property { function } onSelectAll - Колбек, который передает массив с id всех строк таблицы.
 * @property { string[] } selectedRows - Массив id выделенных в данный момент строк.
 * @property { boolean } striped - Если true фон строк таблицы будет чередоваться светлый/темнее.
 * @returns { React.ReactElement } - Элемент таблицы. 
 */
const Table = React.forwardRef<HTMLTableElement, ITableProps>((
    {
        className,
        columnList,
        rowList,
        enableActions,
        enableCheckbox,
        onSelect,
        onSelectAll,
        selectedRows,
        striped,
        rowClick

    }: ITableProps,

    ref

): React.ReactElement => {

    /**
    * Переключает значение переменной, отвечающей за тон строк таблицы.
    * 
    * @returns { () => boolean } - Коллбэк функция, которая при каждом вызове переключает значение tone.
    */
    function toggleRowColor(startTone?: boolean): () => boolean {

        let tone = startTone ?? true;

        return () => {
            tone = !tone;
            return tone;
        };
    }

    /** 
     * Коллбэк функция для переключения тона строк таблицы.
     * 
     * @type { () => boolean }
     */
    const toggleRowColorCallback = toggleRowColor();

    /**
    * Обрабатывает функциональность выбора всех элементов.
    *
    * @return { void }
    */
    const handleSelectAll = () => {

        onSelectAll(rowList.reduce((accumulator, currentValue) => {
            if (!currentValue.disabled) accumulator.push(currentValue.id);
            return accumulator;
        }, []));
    };

    /**
     * Проверяет являются ли все строки отключенными.
     * 
     * @returns  { void }
     */
    const isAllRowDisabled = () => rowList.filter(el => !el.disabled).length === 0;

    /**
     * @function renderCheckboxHeader - Рендерит заголовок с чекбоксом для таблицы.
     * @returns { React.ReactElement } - Заголовок с чекбоксом.
     */
    const renderCheckboxHeader = () => (

        <StyledTH className="checkbox">
            <Checkbox
                disabled={isAllRowDisabled()}
                data-testid="header-checkbox"
                checked={
                    !isAllRowDisabled()
                    && (selectedRows?.length === rowList?.filter(el => !el.disabled).length)
                }
                indeterminate={
                    !isAllRowDisabled()
                    && (selectedRows?.length >= 1)
                }
                coloration="#000"
                onChange={handleSelectAll}
            />
        </StyledTH>
    );

    /**
     * @function renderColumnHeaders -  Рендерит заголовки столбцов таблицы.
     * @returns { React.ReactElement } - Заголовки столбцов.
     */
    const renderColumnHeaders = () => (

        columnList?.map(column => (
            <React.Fragment key={`header_${column.name}`}>
                {
                    enableActions && column.name === "actions" &&
                    <StyledTH>{column.title}</StyledTH>
                }
                {
                    column.name !== "actions" &&
                    <StyledTH>{column.title}</StyledTH>
                }
            </React.Fragment>
        ))
    );

    /**
     * @function rebderCheckboxColumn - Рендерит столбец с чекбоксом для строки таблицы.
     * @returns { React.ReactElement } - Столбец с чекбоксом.
     */
    const renderCheckboxColumn = (row: RowDataType) => (

        <StyledTD className="checkbox" key={`col_${row.id}`}>
            <Checkbox
                data-testid="checkbox"
                coloration="#000"
                checked={selectedRows?.includes(row.id)}
                disabled={row.disabled}
                readOnly
                onChange={() => { onSelect(row.id) }}
                onClick={(event: React.MouseEvent<HTMLInputElement>) => { event.stopPropagation() }}
            />
        </StyledTD>
    );

    /**
     * @function renderDataColumns - Рендерит столбцы данных для заданной строки.
     * @return { React.ReactElement } - Столбцы данных.
     */
    const renderDataColumns = (row: RowDataType) => (

        columnList?.map(column => (
            <React.Fragment key={column.name}>
                {
                    enableActions && column.name === "actions" &&
                    <StyledTD className={column.name === "actions" && "actions"}>
                        {row[column.name]}
                    </StyledTD>
                }
                {
                    column.name !== "actions" &&
                    <StyledTD className={column.name === "id" && "id"}>
                        {row[column.name]}
                    </StyledTD>
                }
            </React.Fragment>
        ))
    );

    /**
     * @function renderTableHead - Рендерит компонент заголовка таблицы или null,
     *  если columnList пуст и enableCheckbox равно false.
     * @return { React.ReactElement } - Компонент заголовка.
     */
    const renderTableHead = () => {

        if (!columnList) {
            return null;
        }

        return (
            <StyledTHead>
                <StyledTR>
                    {enableCheckbox && renderCheckboxHeader()}
                    {columnList && renderColumnHeaders()}
                </StyledTR>
            </StyledTHead>
        );
    };

    /**
     * @function renderTableBody - Отображенное тело таблицы или null,
     *  если rowList пуст и enableCheckbox равно false.
     * @returns { React.ReactElement } - Тело таблицы.
     */
    const renderTableBody = () => {

        if (!rowList) {
            return null;
        }

        return (
            <StyledTBody>
                {rowList.map(row => (
                    <StyledTR
                        disabled={row.disabled}
                        key={row.id}
                        isDark={striped && toggleRowColorCallback()}
                        isChecked={selectedRows?.includes(row.id)}
                        onClick={rowClick && ((event: React.MouseEvent<HTMLTableRowElement>) => {
                            if (!(event.target instanceof HTMLLabelElement)) {
                                rowClick(row.id);
                            }
                        })}
                    >
                        {enableCheckbox && renderCheckboxColumn(row)}
                        {renderDataColumns(row)}
                    </StyledTR>
                ))}
            </StyledTBody>
        );
    };

    return (
        <StyledTable ref={ref} className={className}>
            {renderTableHead()}
            {renderTableBody()}
        </StyledTable>
    );
});

Table.displayName = "Table";

export default Table;